home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / TPNETBIO.ARJ / NETBIOS.PAS < prev    next >
Pascal/Delphi Source File  |  1991-10-21  |  18KB  |  577 lines

  1. {$A+,B-,D+,E-,F-,G-,I+,L+,N-,O-,R+,S+,V-,X-}
  2. {$M 30000,0,50000}
  3.  
  4. {                      Turbo Pascal NetBios Interface
  5.                           Written by Alon Gingold
  6.                              Hitch Hiker's BBS
  7.                                   Israel
  8.  
  9.    This Interface represents many hours of work, and of "why for god's sake
  10.    does'nt it work ???" so  if you decide to use this Interface in your
  11.    programs, please send your contributions to me.
  12.    Anything more then 5 USD will do. Please note that if you send a cheque,
  13.    then sending less then 10 USD will most likely cost me more then the
  14.    cheque's value itself !
  15.  
  16.    Please post your contributions to :
  17.  
  18.    Alon Gingold
  19.    P.O.B 450
  20.    Raanana
  21.    Israel 43104
  22.  
  23.  
  24.    Introduction
  25.    ------------
  26.  
  27.    This unit is an interface to a comunication way used on some LAN systems
  28.    called NetBios. As far as I know, the only system on which NetBios is not
  29.    built in, is NOVEL, but there is a small utility that comes with Novel
  30.    to give it the NetBios support.
  31.  
  32.    So, why do I need to comunicate using netbios, if I can simply write to the
  33.    remote's Disk ??  well, I asked myself the same question some time ago, and
  34.    decided to try. I wrote a program the sent pages after a request was recived
  35.    from a remote. the request was written to the host's ramdisk, and the reply
  36.    was written there as well, and read by the remote. it took about 1 sec. for
  37.    the screen to be transfered (It takes some time for the host to prepair the
  38.    screen).
  39.    After I rewritten the program using this NetBios interface, I could send
  40.    about 5 screens per sec !
  41.  
  42.    I have used CBIS's Netbios text file documentation to learn about NetBios.
  43.    I have included the COMPLETE package of CBIS's text file with no changes
  44.    to the text. That text file is copyrighted by them , and is only added
  45.    here to make it easier for you to find it. it is not a part of my work.
  46.  
  47.    TIPS
  48.    ----
  49.  
  50.    1. Never use DataGrams ! they stinks ! when you receive one DataGram , you
  51.       loose two others.
  52.  
  53.    2. When local names are added to the list, it is , sometimes, imposible
  54.       to delete them from the list. The fact is , that adding and deleting
  55.       names from the list takes quite a while (2 - 3 sec. on lantastic)
  56.       If you write a program that you run, exit from ,and run it again, you
  57.       should NOT try to delete the local name , but simply use the NetStatus
  58.       command , and search to see if the name is allready there. If it is,
  59.       use it, if not, add it.
  60.  
  61.    3. Local names must be unique to each computer on the lan. If you write
  62.       a program that uses a specific name, run it on one computer, then try
  63.       to run it on another computer, you'll get error. As sometimes it is
  64.       imposible to delete a name from the local list, you better use unique
  65.       names on each computer...
  66.  
  67.    4. Never call non POST netbios functions from a POST routine. a post routine
  68.       should update a global table, and a global pointer of that table, and
  69.       then execute the same command that brought up the post, with a post to
  70.       itself. this is most likely a LISTEN command.
  71.  
  72.    5. NetBios's CANCEL command does'nt work that good. it is advised not to use
  73.       it. The way to cancel POST routines is as follows :
  74.  
  75.       A. add an IF in the post routine , that if a specific boolean is true,
  76.          don't execute the Post command again.
  77.  
  78.       B. set that boolean to true.
  79.  
  80.       C. add another name (save the original name, name nunmber) and send a
  81.          command to match the post routine (i.e. A CALL to a listen post).
  82.          then HangUp that session.
  83.  
  84.  
  85. }
  86.  
  87.  
  88.  
  89. Unit NetBios;
  90. interface
  91. uses Dos,service;
  92.  
  93. Const                             {Command number}
  94.   NC_Reset            = $32;
  95.   NC_Cancel           = $35;
  96.   NC_AddName          = $30;
  97.   NC_DelName          = $31;
  98.   NC_AddGroup         = $36;
  99.   NC_Call             = $10;
  100.   NC_Listen           = $11;
  101.   NC_HangUp           = $12;
  102.   NC_ReceiveAny       = $16;
  103.   NC_Receive          = $15;
  104.   NC_Send             = $14;
  105.   NC_SendDataGram     = $20;
  106.   NC_ReceiveDataGram  = $21;
  107.   NC_GetStatus        = $34;
  108.   NC_GetAdapterStatus = $33;
  109.  
  110.   Listen_TimeOut :Byte = 2;       {TimeOuts on several Commands}
  111.   Recive_TimeOut :Byte = 10;
  112.   Send_TimeOut :Byte  = 10;
  113.   Call_TimeOut :Byte = 10;
  114.  
  115.   Net_NoWait : Boolean = False;   {Generate a POST call. Turn this on}
  116.   Net_Jump : Pointer = Nil;       {and set this Pointer to location to
  117.                                   {jump to when the function ends}
  118.                                   {don't forget to turn the boolean off}
  119.                                   {after the call !}
  120.  
  121.  
  122. Type
  123.   NetBiosType = Record
  124.                   Command:Byte;       {Command to execute}
  125.                   RetCode:Byte;       {Return Code, 0 if ok}
  126.                   LSN:Byte;           {Local Session Number}
  127.                   Num:Byte;           {Name Number}
  128.                   BufAdr:Pointer;     {Address of Message Buffer}
  129.                   BufLen:Integer;     {Length of message, up to 512}
  130.                   CallName:String[15];{Name to call, don't use as string!!!}
  131.                   Name:String[15];    {Local Name used  "   "    "  "}
  132.                   RTO:Byte;           {Recieve Time Out 0.5 incr}
  133.                   STO:Byte;           {Send Time Out in 0.5 incr}
  134.                   Post:Pointer;       {Address of User Interupt routine}
  135.                   LANA_Num:Byte;      {Number of Adapter card}
  136.                   CMD_Done:Byte;      {Command Completed Flag.}
  137.                   RES:String[13]      {Internal use of NetBios}
  138.                 end;
  139.  
  140.  
  141.   NetStatusType = record
  142.                     NameNum:Byte;
  143.                     Sessions:Byte;
  144.                     OutStandingDataGram:Byte;
  145.                     OutStanding:Byte;
  146.                     S:Array[1..20] of Record
  147.                       LSN:Byte;
  148.                       State:Byte;
  149.                       Name:String[15];
  150.                       CallName:String[15];
  151.                       OutStandingDataGram:Byte;
  152.                       OutStanding:Byte;
  153.                     end;
  154.                   end;
  155.  
  156.   NetAdapterStatusType = record
  157.                            Node:String[5];
  158.                            Jumper:byte;
  159.                            Power:Byte;
  160.                            version:Word;
  161.                            minutes:Word;
  162.                            CrcErrors:Word;
  163.                            AlignErrors:Word;
  164.                            TransErrors:Word;
  165.                            AbortErrors:Word;
  166.                            SentPacketes:LongInt;
  167.                            RecvPacketes:LongInt;
  168.                            Retransmits:word;
  169.                            OutofBuffers:Word;
  170.                            Reserved:array[1..8] of byte;
  171.                            NCBFree:Word;
  172.                            ResetNCB:Word;
  173.                            MaxResetNCB:Word;
  174.                            Reserved2:array[1..4] of byte;
  175.                            ActiveSessions:Word;
  176.                            ResetSessions:Word;
  177.                            MaxResetSessions:Word;
  178.                            PackMaxLen:Word;
  179.                            NamesNum:Word;
  180.                            Names:Array[1..20] of record
  181.                              Name:String[15];
  182.                              Num:Byte;
  183.                              Status:Byte;
  184.                            end;
  185.                          end;
  186.  
  187.  
  188. var
  189.   Net_Name:String[15];  {Name of this local machine}
  190.   Net_NameNum:Byte;     {Name Number}
  191.   Net_LastError:Byte;   {Last Error}
  192.   NetB:NetBiosType;     {The NCB that is used on most commands.}
  193.                         {Listen uses a user's NCB cause it's used}
  194.                         {mostly for post}
  195.  
  196.  
  197. procedure PutString(var Dest:String; Source:String; l:integer);
  198. {
  199.   Takes the source PASCAL string and puts it in the ASCIIZ (zero terminated)
  200.   string in Dest. note that the DEST string is used from possition zero !
  201.   l is the length of the Dest string (paded with zeros) should be equal
  202.   to the sizeof(dest) - or to the Dest string length + 1
  203. }
  204.  
  205. procedure GetString(Source:String; var Dest:String; l:integer);
  206. {
  207.   The oposite of PutString..
  208.   Takes the ASCIIZ string from Source with the length l, and puts it into
  209.   Pascal's Dest string
  210. }
  211.  
  212. {               All the following routines return FALSE if an error had
  213.                 occoured. The error numer is found in the Net_LastError
  214.                 The strings are PASCAL strings. the asciiz translation
  215.                 is automaticaly done.
  216. }
  217.  
  218.  
  219. procedure Net_Do(var NetB:NetBiosType);
  220. {
  221.   Execute the NetBios command in NetB. this will call NetBios with or without
  222.   POST as in Net_NoWait boolean, and return the error in Net_LastError.
  223. }
  224.  
  225.  
  226. Function Net_Reset:Boolean;
  227. {
  228.   Reset the NetBios. This is a NO NO ! , a reset on lantastic caused the
  229.   computer to be disconnected from the rest of the lan !
  230. }
  231.  
  232.  
  233. Function Net_Cancel(var NetBOld:NetBiosType):boolean;
  234. {
  235.   Cancel the NetBios command in the NCB pointed bt NetBOld
  236.   This does'nt allways work, and should not be used if other ways could be
  237.   insted
  238. }
  239.  
  240.  
  241. Function Net_AddName(NameSt:String):Boolean;
  242. {
  243.   Add a name to the local name table. The name will be saved in Net_Name.
  244.   The Name number is entered into Net_NameNum.
  245.   Only the last name added is saved , and if more then one name is used, they
  246.   must be saved by the user (Name Numbers as well)
  247. }
  248.  
  249. Function Net_DelName:Boolean;
  250. {
  251.   Delete the name that is in the Net_Name.
  252. }
  253.  
  254.  
  255. Function Net_AddGroup(Name:String):Boolean;
  256. {
  257.   Add a GROUP name. this is used for the broadCast messages. BroadCasts are not
  258.   implemented in this interface, but can be easily implemented from the Data
  259.   Gram equavalents
  260. }
  261.  
  262.  
  263.  
  264. Function Net_Call(CallToName:String; var SessionNum:byte):Boolean;
  265. {
  266.   Call a remote computer. SessionNum returnes the Session Number if the call
  267.   was successfull
  268. }
  269.  
  270.  
  271. Function Net_Listen(var NetB:NetBiosType; var NameCalled:string; var SessionNum:byte):Boolean;
  272. {
  273.   Listen for Calls. NetB is a user NetBiosType. I made it use a different
  274.   NetBios var , as I used it as a POST routine.
  275.   NameCalled should have a name to listen to , or * for all systems, and will
  276.   return the name of the calling computer , if * was used
  277.   SessionNum returns the Session number , if successfull.
  278. }
  279.  
  280. Function Net_Receive(ReceiveFrom:Byte; var MsgTxt; var MsgLen:Integer):Boolean;
  281. {
  282.   Recive data from an online session. SessionNumber should be in ReciveFrom,
  283.   MsgTxt is a pointer to the buffer, and MsgLen should have the maximum msg
  284.   length to receive. It will be changed to the actuall size of the msg recived
  285. }
  286.  
  287. Function Net_ReceiveAny(var MsgTxt; var MsgLen:Integer; var Session:byte):Boolean;
  288. {
  289.   Recived from any online session. Session will return the session the msg was
  290.   recived from
  291. }
  292.  
  293. Function Net_Send(SendToSession:Byte; var MsgTxt; var MsgLen:Integer):Boolean;
  294. {
  295.   Send data to an online session. MsgLen should have the size of the message
  296.   as pointed by MsgTxt
  297. }
  298.  
  299. Function Net_SendDataGram(CallToName:String; var MsgTxt; var MsgLen:Integer):Boolean;
  300. {
  301.   Send DataGram to CallToName. max size is 512 byte
  302. }
  303.  
  304. Function Net_ReceiveDataGram(Num:byte; var NameCalled:string; var MsgTxt; var MsgLen:Integer):Boolean;
  305. {
  306.   Recived DataGram to Name Number Num. NameCalled will return the name of the
  307.   remote computer who sent the datagram, MsgTxt is a pointer to where the
  308.   message will be written to, and MsgLen is the max length (will return the
  309.   actuall size
  310.  
  311. }
  312.  
  313. Function Net_GetStatus(Var Status:NetStatusType):Boolean;
  314. {
  315.   Get NetStatus.
  316. }
  317.  
  318. Function Net_GetAdapterStatus(Var Status:NetAdapterStatusType):Boolean;
  319. {
  320.   Get Adapter Status.
  321. }
  322.  
  323. Function Net_HangUp(SessionNum:Byte):Boolean;
  324. {
  325.   HangUp session number SessionNum
  326. }
  327.  
  328. function Net_NameRestore(NameToRestore:String):boolean;  {Restore Specific name from name table}
  329. {
  330.   Retrive NameToRestore from the local name table. if found, Net_Name, and
  331.   Net_NameNum will be set.
  332. }
  333.  
  334.  
  335. implementation
  336.  
  337.  
  338. procedure PutString(var Dest:String; Source:String; l:integer);
  339. var
  340.   i:integer;
  341. begin
  342.   fillChar(Dest,l,#0);
  343.   for i := 1 to length(source) do Dest[i-1] := Source[i];
  344. end;
  345.  
  346. procedure GetString(Source:String; var Dest:String; l:integer);
  347. var
  348.   i:integer;
  349. begin
  350.   Dest := '';
  351.   i := 0;
  352.   while (Source[i] <> #0) and (i<=l) do begin
  353.     Dest[i+1] := Source[i];
  354.     inc(i);
  355.   end;
  356.   Dest[0] := char(i);
  357. end;
  358.  
  359.  
  360. procedure Net_Do(var NetB:NetBiosType);
  361. var
  362.   reg:Registers;
  363. begin
  364.   if Net_NoWait then begin
  365.     NetB.Command := NetB.Command or $80;
  366.     if Net_Jump <> nil then NetB.Post := Net_Jump;
  367.   end;
  368.   Reg.ES := seg(NetB);
  369.   Reg.BX := ofs(NetB);
  370.   Intr($5C,Reg);
  371.   Net_LastError := NetB.RETCode;
  372. end;
  373.  
  374.  
  375. Function Net_Reset:Boolean;
  376. begin
  377.   FillChar(NetB,sizeof(NetBiosType),#0);
  378.   NetB.Command := NC_Reset;  {Reset Net Bios}
  379.   Net_Do(NetB);
  380.   Net_Reset := (NetB.RetCode = 0);
  381. end;
  382.  
  383. Function Net_Cancel(var NETBOLD:NetBiosType):boolean;
  384. var
  385.   NetB:NetBiosType;
  386. begin
  387.   FillChar(NetB,sizeof(NetBiosType),#0);
  388.   NetB.Command := NC_Cancel;
  389.   NetB.BufAdr := addr(NetBold);
  390.   PutString(NetB.Name,Net_Name,16);
  391.   Net_Do(NetB);
  392.   Net_NameNum := NetB.Num;
  393.   Net_Cancel := (NetB.RetCode = 0);
  394. end;
  395.  
  396.  
  397. Function Net_AddName(NameSt:String):Boolean;
  398. begin
  399.   Net_Name := NameSt;
  400.   FillChar(NetB,sizeof(NetBiosType),#0);
  401.   NetB.Command := NC_AddName;
  402.   PutString(NetB.Name,Net_Name,16);
  403.   Net_Do(NetB);
  404.   Net_NameNum := NetB.Num;
  405.   Net_AddName := (NetB.RetCode = 0);
  406. end;
  407.  
  408.  
  409. Function Net_DelName:Boolean;
  410. begin
  411.   FillChar(NetB,sizeof(NetBiosType),#0);
  412.   NetB.Command := NC_DelName;
  413.   PutString(NetB.Name,Net_Name,16);
  414.   Net_Do(NetB);
  415.   Net_DelName := (NetB.RetCode = 0);
  416. end;
  417.  
  418.  
  419. Function Net_AddGroup(Name:String):Boolean;
  420. begin
  421.   FillChar(NetB,sizeof(NetBiosType),#0);
  422.   NetB.Command := NC_AddGroup;
  423.   PutString(NetB.Name,Name,16);
  424.   Net_Do(NetB);
  425.   Net_AddGroup := (NetB.RetCode = 0);
  426. end;
  427.  
  428. Function Net_Call(CallToName:String; var SessionNum:byte):Boolean;
  429. begin
  430.   FillChar(NetB,sizeof(NetBiosType),#0);
  431.   NetB.Command := NC_Call;
  432.   PutString(NetB.Name,Net_Name,16);
  433.   PutString(NetB.CallName,CallToName,16);
  434.   NetB.RTO := Call_TimeOut;
  435.   NetB.STO := Call_TimeOut;
  436.   {directwrite(Net_Name,5,20);
  437.   directwrite(CallToName,20,20);}
  438.   Net_Do(NetB);
  439.   SessionNum := NetB.LSN ;
  440.   Net_Call := (NetB.RetCode = 0);
  441. end;
  442.  
  443. Function Net_Listen(var NetB:NetBiosType; var NameCalled:string; var SessionNum:byte):Boolean;
  444. begin
  445.   FillChar(NetB,sizeof(NetBiosType),#0);
  446.   NetB.Command := NC_Listen;
  447.   PutString(NetB.Name,Net_Name,16);
  448. { NameCalled := '*';}
  449.   PutString(NetB.CallName,NameCalled,16);
  450.   NetB.RTO := Listen_TimeOut;
  451.   NetB.STO := Listen_TimeOut;
  452.   {directwrite(Net_Name,5,20);
  453.   directwrite(NameCalled,20,20);}
  454.   Net_Do(NetB);
  455.   GetString(NetB.CallName,NameCalled,16);
  456.   SessionNum := NetB.LSN ;
  457.   Net_Listen := (NetB.RetCode = 0);
  458. end;
  459.  
  460.  
  461. Function Net_ReceiveAny(var MsgTxt; var MsgLen:Integer; var Session:byte):Boolean;
  462. begin
  463.   FillChar(NetB,sizeof(NetBiosType),#0);
  464.   NetB.Command := NC_ReceiveAny;
  465.   NetB.Num := $FF;  {Recive messages from All callers}
  466.   NetB.BufAdr := addr(MsgTxt);
  467.   NetB.BufLen := MsgLen;
  468.   Net_Do(NetB);
  469.   Session := NetB.LSN;
  470.   MsgLen := NetB.BufLen;
  471.   Net_ReceiveAny := (NetB.RetCode = 0);
  472. end;
  473.  
  474. Function Net_Receive(ReceiveFrom:Byte; var MsgTxt; var MsgLen:Integer):Boolean;
  475. begin
  476.   FillChar(NetB,sizeof(NetBiosType),#0);
  477.   NetB.Command := NC_Receive;
  478.   NetB.LSN := ReceiveFrom;
  479.   NetB.BufAdr := addr(MsgTxt);
  480.   NetB.BufLen := MsgLen;
  481.   Net_Do(NetB);
  482.   MsgLen := NetB.BufLen;
  483.   Net_Receive := (NetB.RetCode = 0);
  484. end;
  485.  
  486. Function Net_Send(SendToSession:Byte; var MsgTxt; var MsgLen:Integer):Boolean;
  487. begin
  488.   FillChar(NetB,sizeof(NetBiosType),#0);
  489.   NetB.Command := NC_Send;
  490.   NetB.LSN := SendToSession;
  491.   NetB.BufAdr := addr(MsgTxt);
  492.   NetB.BufLen := MsgLen;
  493.   Net_Do(NetB);
  494.   Net_Send := (NetB.RetCode = 0);
  495. end;
  496.  
  497. Function Net_SendDataGram(CallToName:String; var MsgTxt; var MsgLen:Integer):Boolean;
  498. begin
  499.   FillChar(NetB,sizeof(NetBiosType),#0);
  500.   NetB.Command := NC_SendDataGram;
  501.   PutString(NetB.CallName,CallToName,16);
  502.   NetB.Num := Net_NameNum;
  503.   NetB.BufAdr := addr(MsgTxt);
  504.   NetB.BufLen := MsgLen;
  505.   Net_Do(NetB);
  506.   Net_SendDataGram := (NetB.RetCode = 0);
  507. end;
  508.  
  509. Function Net_ReceiveDataGram(Num:Byte; var NameCalled:string; var MsgTxt; var MsgLen:Integer):Boolean;
  510. begin
  511.   FillChar(NetB,sizeof(NetBiosType),#0);
  512.   NetB.Command := NC_ReceiveDataGram;
  513.   NetB.Num := Num;
  514.   NetB.BufAdr := addr(MsgTxt);
  515.   NetB.BufLen := MsgLen;
  516.   Net_Do(NetB);
  517.   GetString(NetB.CallName,NameCalled,16);
  518.   MsgLen := NetB.BufLen;
  519.   Net_ReceiveDataGram := (NetB.RetCode = 0);
  520. end;
  521.  
  522.  
  523. Function Net_GetStatus(Var Status:NetStatusType):Boolean;
  524. begin
  525.   FillChar(NetB,sizeof(NetBiosType),#0);
  526.   NetB.Command := NC_GetStatus;
  527.   NetB.BufAdr := addr(Status);
  528.   NetB.BufLen := sizeof(Status);
  529.   PutString(NetB.Name,Net_Name,16);
  530.   Net_Do(NetB);
  531.   Net_GetStatus := (NetB.RetCode = 0);
  532. end;
  533.  
  534. Function Net_GetAdapterStatus(Var Status:NetAdapterStatusType):Boolean;
  535. begin
  536.   FillChar(NetB,sizeof(NetBiosType),#0);
  537.   NetB.Command := NC_GetAdapterStatus;
  538.   NetB.BufAdr := addr(Status);
  539.   NetB.BufLen := sizeof(Status);
  540.   PutString(NetB.Name,Net_Name,16);
  541.   PutString(NetB.CallName,'*',16);
  542.   Net_Do(NetB);
  543.   Net_GetAdapterStatus := (NetB.RetCode = 0);
  544. end;
  545.  
  546. Function Net_HangUp(SessionNum:Byte):Boolean;
  547. begin
  548.   FillChar(NetB,sizeof(NetBiosType),#0);
  549.   NetB.Command := NC_HangUp;
  550.   NetB.LSN := SessionNum;
  551.   Net_Do(NetB);
  552.   Net_HangUp := (NetB.RetCode = 0);
  553. end;
  554.  
  555. function NET_NameRestore(NameToRestore:String):boolean;
  556. var
  557.   Status:NetAdapterStatusType;
  558.   Name:String;
  559. begin
  560.   Net_Name := '';
  561.   if Net_GetAdapterStatus(Status) then begin
  562.     for i := 1 to Status.Namesnum do begin
  563.       GetString(Status.Names[i].Name,name,16);
  564.       if Name = NameToRestore then begin
  565.         Net_Name := Name;
  566.         Net_NameNum := Status.Names[i].Num;
  567.       end;
  568.     end;
  569.   end;
  570.   NET_NameRestore := (Net_Name=NameToRestore);
  571. end;
  572.  
  573.  
  574. begin
  575.   Net_Name := '';
  576. end.
  577.